package com.dominator.utils.pay;

import com.dominFramework.core.typewrap.Dto;
import com.dominFramework.core.typewrap.Dtos;
import com.dominFramework.core.utils.JsonUtils;
import com.dominFramework.core.utils.SystemUtils;
import com.dominator.utils.dao.RedisUtil;
import com.dominator.utils.encode.Des3Utils;
import com.dominator.utils.exception.ApiException;
import com.dominator.utils.system.PropertiesLoader;
import com.dominator.utils.system.SeemseUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.dom4j.Element;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
@Slf4j
public class WeixinSign {

    private static RedisUtil ru = RedisUtil.getRu();

    public static final String WX_PREPAY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    public static PropertiesLoader propertiesLoader = new PropertiesLoader("sysconfig.properties");


    public static Dto sign(String jsapi_ticket, String url) {
        Dto resDto = Dtos.newDto();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写，且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + nonce_str +
                "&timestamp=" + timestamp +
                "&url=" + url;
        System.out.println(string1);

        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        resDto.put("url", url);
        resDto.put("jsapi_ticket", jsapi_ticket);
        resDto.put("nonceStr", nonce_str);
        resDto.put("timestamp", timestamp);
        resDto.put("signature", signature);
        resDto.put("appId", propertiesLoader.getProperty("wx_api_id"));


        return resDto;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    private static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    /**
     * url签名
     *
     * @param url
     * @return
     */
    public static Dto getParamsByUrl(String url) {
        String accessToken = getAccessToken();
        String resStr = HttpKit.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" + accessToken);
        Dto dto = JsonUtils.toDto(resStr);
        String ticket = dto.getString("ticket");
        return sign(ticket, url);
    }


    /**
     * 获取accessToken
     *
     * @return
     */
    public static String getAccessToken() {
        String accessToken = ru.get("access_token");
        System.out.println("redis读取access_token:" + accessToken);
        if (SystemUtils.isEmpty(accessToken)) {
            // 注意 URL 一定要动态获取，不能 hardcode
            System.out.println("接口获取access");
            String resStr = HttpKit.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + propertiesLoader.getProperty("wx_api_id") + "&secret=" + propertiesLoader.getProperty("wx_api_secret"));
            Dto dtos = JsonUtils.toDto(resStr);
            accessToken = dtos.getString("access_token");
            //access_token放入redis
            ru.setex("access_token", accessToken, 7000);
        }
        return accessToken;

    }


    /**
     * 微信签名(公众号)
     *
     * @param total_fee(支付金额【元】)；
     * @param spbill_create_ip（用户端实际ip）
     * @return ApiMessage
     * @throws ApiException
     */
    public static Map<String, String> wxSignPublic(double total_fee, String spbill_create_ip, String name,
                                                   String trade_type, String openid) throws ApiException {
        SortedMap<String, Object> signMap = new TreeMap<String, Object>();
        // 微信开放平台审核通过的应用APPID
        signMap.put("appid", propertiesLoader.getProperty("wx_mch_public_appid"));
        // 微信商户号
        signMap.put("mch_id", propertiesLoader.getProperty("wx_mch_public_id"));
        // 随机字符串
        signMap.put("nonce_str", SeemseUtil.randoms().toUpperCase());
        // 商品描述
        signMap.put("body", name);
        // 用户唯一标识符
        signMap.put("openid", openid);
        // 商户订单号
        signMap.put("out_trade_no", SeemseUtil.getCurrentTime() + "W");
        // 总金额
        signMap.put("total_fee", (int) (total_fee * 100));
        signMap.put("sign_type", "MD5");
        // 用户端实际ip
        signMap.put("spbill_create_ip", spbill_create_ip);
        // 异步通知地址
        signMap.put("notify_url", propertiesLoader.getProperty("wx_notify_url_public"));
        // 交易类型
        signMap.put("trade_type", trade_type);
        /** 调用签名方法 **/
        String sign = createSign(signMap, propertiesLoader.getProperty("wx_mch_public_key"));
        signMap.put("sign", sign);
        return unifiedOrderPublic(signMap, trade_type, openid);

    }

    /**
     * 微信签名
     *
     * @param sorted
     * @param key
     * @return
     */
    public static String createSign(SortedMap<String, Object> sorted, String key) {
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<String, Object>> entries = sorted.entrySet(); // 所有参与传参的参数按照accsii排序（升序）
        for (Map.Entry<String, Object> entry : entries) {
            if (!(SystemUtils.isEmpty(entry.getValue()) || "sign".equals(entry.getKey()))) {
                sb.append(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        System.out.println("key=" + key);
        sb.append("key=" + key);
        System.err.println(sb.toString());
        String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
        System.out.println("------" + sign);
        return sign;
    }


    /**
     * 微信预支付订单
     *
     * @return ApiMessage
     * @throws ApiException
     */
    public static Map<String, String> unifiedOrderPublic(SortedMap<String, Object> signMap, String trade_type,
                                                         String openid) throws ApiException {
        // 生成订单号
        Map<String, String> map = new HashMap<String, String>();
        map.put("appid", signMap.get("appid").toString());// 应用ID
        map.put("body", signMap.get("body") + "");// 商品描述
        map.put("mch_id", signMap.get("mch_id").toString());// 商户号
        map.put("nonce_str", signMap.get("nonce_str") + "");// 随机字符串
        map.put("notify_url", signMap.get("notify_url") + "");// 通知地址
        map.put("openid", openid);
        map.put("out_trade_no", signMap.get("out_trade_no") + "");// 商户订单号
        map.put("sign_type", "MD5");
        map.put("spbill_create_ip", signMap.get("spbill_create_ip") + "");// 终端IP
        map.put("total_fee", signMap.get("total_fee") + "");// 总金额
        map.put("trade_type", signMap.get("trade_type") + "");// 交易类型
        map.put("sign", signMap.get("sign") + "");
        // 用户唯一标识符
        // 进行xml格式拼接
        String xml = SeemseUtil.createXml(map);
        System.out.println(xml);
        // 接收接口返回值
        String returnXml = HttpKit.post(WX_PREPAY_URL, xml);
        System.out.println("获取订单成功");
        System.out.println(returnXml);
        // 解析xml格式数据
        Element root = XmlParser.doParse(returnXml);
        System.out.println(root.toString());
        // 获取返回状态
        String returnCode = root.elementTextTrim("return_code");
        String resultCode = root.elementText("result_code");
        System.out.println(returnCode + "------" + resultCode);
        if (returnCode.equals("SUCCESS") && resultCode.equals("SUCCESS")) {
            System.err.println("结果验证");
            long currentTimeMillis = System.currentTimeMillis();// 生成时间戳
            System.err.println(currentTimeMillis);
            long second = currentTimeMillis / 1000L;// （转换成秒）
            Map<String, String> resMap = new HashMap<String, String>();
            resMap.put("nonce_str", map.get("nonce_str"));
            resMap.put("prepay_id", "prepay_id=" + root.elementText("prepay_id"));
            resMap.put("out_trade_no", signMap.get("out_trade_no") + "");
            resMap.put("appId", map.get("appid") + "");
            resMap.put("timeStamp", second + "");
            resMap.put("signType", "MD5");
            // 二次签名（微信公众号支付传参paySign需要nonceStr、package、appId、timeStamp、signType参与签名）
            SortedMap<String, Object> signMaps = new TreeMap<String, Object>();
            signMaps.put("nonceStr", map.get("nonce_str"));
            signMaps.put("package", "prepay_id=" + root.elementText("prepay_id"));
            signMaps.put("appId", map.get("appid") + "");
            signMaps.put("timeStamp", second + "");
            signMaps.put("signType", "MD5");
            String sign = createSign(signMaps, propertiesLoader.getProperty("wx_mch_public_key"));
            resMap.put("sign", sign);
            System.err.println("返回结果:" + Des3Utils.encResponse(resMap));
            return resMap;
        }
        throw new ApiException("105", "获取订单失败");
    }

    /**
     * 下载微信图片资源
     *
     * @param mediaId
     * @return
     */
    public static byte[] downloadMedia(String mediaId) {
        String accessToken = WeixinSign.getAccessToken();
        String requestUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + accessToken + "&media_id=" + mediaId;
        InputStream in = null;
        HttpURLConnection conn = null;
        byte[] filebyte = new byte[0];
        try {
            URL url = new URL(requestUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoInput(true);
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(30000);
            BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            byte[] buff = new byte[100];
            int rc = 0;
            while ((rc = bis.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            filebyte = swapStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return filebyte;
    }


    /**
     * 根据微信openId获取用户信息
     *
     * @param openId
     * @return
     */
    public static String getUserInfoByOpenId(String openId) {
        String accessToken = WeixinSign.getAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openId+"&lang=zh_CN";
        String res = "";
        try {
            res = HttpKit.get(url);
            log.info("微信获取用户信息"+res);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }
}
